home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / XML / RPC.php < prev    next >
PHP Script  |  2004-10-01  |  35KB  |  1,190 lines

  1. <?php
  2. // /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // by Edd Dumbill (C) 1999-2001
  4. // <edd@usefulinc.com>
  5. // $Id: RPC.php,v 1.21 2004/03/15 13:51:44 pajoye Exp $
  6.  
  7. // License is granted to use or modify this software ("XML-RPC for PHP")
  8. // for commercial or non-commercial use provided the copyright of the author
  9. // is preserved in any distributed or derivative work.
  10.  
  11. // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  12. // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  13. // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  14. // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  15. // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  16. // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  17. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  18. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  19. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  20. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21.  
  22. // Adapted to PEAR standards by Stig S∩┐╜her Bakken <stig@php.net> and
  23. // Martin Jansen <mj@php.net>
  24. // /* $id$ */
  25.  
  26. if (!function_exists('xml_parser_create')) {
  27. // Win 32 fix. From: "Leo West" <lwest@imaginet.fr>
  28.     if ($WINDIR) {
  29.         dl("php_xml.dll");
  30.     } else {
  31.         dl("xml.so");
  32.     }
  33. }
  34.  
  35. define('XML_RPC_ERROR_INVALID_TYPE',        101);
  36. define('XML_RPC_ERROR_NON_NUMERIC_FOUND',   102);
  37. define('XML_RPC_ERROR_CONNECTION_FAILED',   103);
  38. define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
  39.  
  40. $GLOBALS['XML_RPC_I4'] = "i4";
  41. $GLOBALS['XML_RPC_Int'] = "int";
  42. $GLOBALS['XML_RPC_Boolean'] = "boolean";
  43. $GLOBALS['XML_RPC_Double'] = "double";
  44. $GLOBALS['XML_RPC_String'] = "string";
  45. $GLOBALS['XML_RPC_DateTime'] = "dateTime.iso8601";
  46. $GLOBALS['XML_RPC_Base64'] = "base64";
  47. $GLOBALS['XML_RPC_Array'] = "array";
  48. $GLOBALS['XML_RPC_Struct'] = "struct";
  49.  
  50. $GLOBALS['XML_RPC_Types'] = array($GLOBALS['XML_RPC_I4'] => 1,
  51.                                 $GLOBALS['XML_RPC_Int'] => 1,
  52.                                 $GLOBALS['XML_RPC_Boolean'] => 1,
  53.                                 $GLOBALS['XML_RPC_String'] => 1,
  54.                                 $GLOBALS['XML_RPC_Double'] => 1,
  55.                                 $GLOBALS['XML_RPC_DateTime'] => 1,
  56.                                 $GLOBALS['XML_RPC_Base64'] => 1,
  57.                                 $GLOBALS['XML_RPC_Array'] => 2,
  58.                                 $GLOBALS['XML_RPC_Struct'] => 3);
  59.  
  60. $GLOBALS['XML_RPC_entities'] = array("quot" => '"',
  61.                                      "amp" => "&",
  62.                                      "lt" => "<",
  63.                                      "gt" => ">",
  64.                                      "apos" => "'");
  65.  
  66. $GLOBALS['XML_RPC_err']["unknown_method"] = 1;
  67. $GLOBALS['XML_RPC_str']["unknown_method"] = "Unknown method";
  68. $GLOBALS['XML_RPC_err']["invalid_return"] = 2;
  69. $GLOBALS['XML_RPC_str']["invalid_return"] = "Invalid return payload: enabling debugging to examine incoming payload";
  70. $GLOBALS['XML_RPC_err']["incorrect_params"] = 3;
  71. $GLOBALS['XML_RPC_str']["incorrect_params"] = "Incorrect parameters passed to method";
  72. $GLOBALS['XML_RPC_err']["introspect_unknown"] = 4;
  73. $GLOBALS['XML_RPC_str']["introspect_unknown"] = "Can't introspect: method unknown";
  74. $GLOBALS['XML_RPC_err']["http_error"] = 5;
  75. $GLOBALS['XML_RPC_str']["http_error"] = "Didn't receive 200 OK from remote server.";
  76.  
  77. $GLOBALS['XML_RPC_defencoding'] = "UTF-8";
  78.  
  79. // let user errors start at 800
  80. $GLOBALS['XML_RPC_erruser'] = 800;
  81.  
  82. // let XML parse errors start at 100
  83. $GLOBALS['XML_RPC_errxml'] = 100;
  84.  
  85. // formulate backslashes for escaping regexp
  86. $GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
  87.  
  88. $GLOBALS['XML_RPC_twoslash'] = $GLOBALS['XML_RPC_backslash'] . $GLOBALS['XML_RPC_backslash'];
  89. $GLOBALS['XML_RPC_twoslash'] = "2SLS";
  90.  
  91. // used to store state during parsing
  92. // quick explanation of components:
  93. //   st - used to build up a string for evaluation
  94. //   ac - used to accumulate values
  95. //   qt - used to decide if quotes are needed for evaluation
  96. //   cm - used to denote struct or array (comma needed)
  97. //   isf - used to indicate a fault
  98. //   lv - used to indicate "looking for a value": implements
  99. //        the logic to allow values with no types to be strings
  100. //   params - used to store parameters in method calls
  101. //   method - used to store method name
  102.  
  103. $GLOBALS['XML_RPC_xh'] = array();
  104.  
  105. function XML_RPC_entity_decode($string)
  106. {
  107.     $top = split("&", $string);
  108.     $op = "";
  109.     $i = 0;
  110.     while($i < sizeof($top)) {
  111.         if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) {
  112.             $op .= ereg_replace("^[#a-zA-Z0-9]+;",
  113.                                 XML_RPC_lookup_entity($regs[1]),
  114.                                 $top[$i]);
  115.         } else {
  116.             if ($i == 0) {
  117.                 $op = $top[$i];
  118.             } else {
  119.                 $op .= "&" . $top[$i];
  120.             }
  121.         }
  122.  
  123.         $i++;
  124.     }
  125.     return $op;
  126. }
  127.  
  128.  
  129. function XML_RPC_lookup_entity($ent)
  130. {
  131.     global $XML_RPC_entities;
  132.  
  133.     if ($XML_RPC_entities[strtolower($ent)]) {
  134.         return $XML_RPC_entities[strtolower($ent)];
  135.     }
  136.  
  137.     if (ereg("^#([0-9]+)$", $ent, $regs)) {
  138.         return chr($regs[1]);
  139.     }
  140.  
  141.     return "?";
  142. }
  143.  
  144.  
  145. function XML_RPC_se($parser, $name, $attrs)
  146. {
  147.     global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
  148.  
  149.     switch ($name) {
  150.     case "STRUCT":
  151.     case "ARRAY":
  152.         $XML_RPC_xh[$parser]['st'] .= "array(";
  153.         $XML_RPC_xh[$parser]['cm']++;
  154.         // this last line turns quoting off
  155.         // this means if we get an empty array we'll
  156.         // simply get a bit of whitespace in the eval
  157.         $XML_RPC_xh[$parser]['qt'] = 0;
  158.         break;
  159.  
  160.     case "NAME":
  161.         $XML_RPC_xh[$parser]['st'] .= "'";
  162.         $XML_RPC_xh[$parser]['ac'] = "";
  163.         break;
  164.  
  165.     case "FAULT":
  166.         $XML_RPC_xh[$parser]['isf'] = 1;
  167.         break;
  168.  
  169.     case "PARAM":
  170.         $XML_RPC_xh[$parser]['st'] = "";
  171.         break;
  172.  
  173.     case "VALUE":
  174.         $XML_RPC_xh[$parser]['st'] .= "new XML_RPC_Value(";
  175.         $XML_RPC_xh[$parser]['lv'] = 1;
  176.         $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
  177.         $XML_RPC_xh[$parser]['ac'] = "";
  178.         $XML_RPC_xh[$parser]['qt'] = 0;
  179.         // look for a value: if this is still 1 by the
  180.         // time we reach the first data segment then the type is string
  181.         // by implication and we need to add in a quote
  182.         break;
  183.  
  184.     case "I4":
  185.     case "INT":
  186.     case "STRING":
  187.     case "BOOLEAN":
  188.     case "DOUBLE":
  189.     case "DATETIME.ISO8601":
  190.     case "BASE64":
  191.         $XML_RPC_xh[$parser]['ac'] = ""; // reset the accumulator
  192.  
  193.         if ($name == "DATETIME.ISO8601" || $name == "STRING") {
  194.             $XML_RPC_xh[$parser]['qt'] = 1;
  195.  
  196.             if ($name == "DATETIME.ISO8601") {
  197.                 $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
  198.             }
  199.  
  200.         } elseif ($name == "BASE64") {
  201.             $XML_RPC_xh[$parser]['qt'] = 2;
  202.         } else {
  203.             // No quoting is required here -- but
  204.             // at the end of the element we must check
  205.             // for data format errors.
  206.             $XML_RPC_xh[$parser]['qt'] = 0;
  207.         }
  208.         break;
  209.  
  210.     case "MEMBER":
  211.         $XML_RPC_xh[$parser]['ac'] = "";
  212.         break;
  213.  
  214.     default:
  215.         break;
  216.     }
  217.  
  218.     if ($name!="VALUE") {
  219.         $XML_RPC_xh[$parser]['lv'] = 0;
  220.     }
  221. }
  222.  
  223.  
  224. function XML_RPC_ee($parser, $name)
  225. {
  226.     global $XML_RPC_xh,$XML_RPC_Types,$XML_RPC_String;
  227.  
  228.     switch ($name) {
  229.     case "STRUCT":
  230.     case "ARRAY":
  231.         if ($XML_RPC_xh[$parser]['cm'] && substr($XML_RPC_xh[$parser]['st'], -1) == ',') {
  232.             $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'],0,-1);
  233.         }
  234.  
  235.         $XML_RPC_xh[$parser]['st'] .= ")";
  236.         $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  237.         $XML_RPC_xh[$parser]['cm']--;
  238.         break;
  239.  
  240.     case "NAME":
  241.         $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . "' => ";
  242.         break;
  243.  
  244.     case "BOOLEAN":
  245.         // special case here: we translate boolean 1 or 0 into PHP
  246.         // constants true or false
  247.         if ($XML_RPC_xh[$parser]['ac'] == '1') {
  248.             $XML_RPC_xh[$parser]['ac'] = "true";
  249.         } else {
  250.             $XML_RPC_xh[$parser]['ac'] = "false";
  251.         }
  252.  
  253.         $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  254.         // Drop through intentionally.
  255.  
  256.     case "I4":
  257.     case "INT":
  258.     case "STRING":
  259.     case "DOUBLE":
  260.     case "DATETIME.ISO8601":
  261.     case "BASE64":
  262.         if ($XML_RPC_xh[$parser]['qt'] == 1) {
  263.             // we use double quotes rather than single so backslashification works OK
  264.             $XML_RPC_xh[$parser]['st'] .= "\"" . $XML_RPC_xh[$parser]['ac'] . "\"";
  265.         } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
  266.             $XML_RPC_xh[$parser]['st'] .= "base64_decode('" . $XML_RPC_xh[$parser]['ac'] . "')";
  267.         } elseif ($name=="BOOLEAN") {
  268.             $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
  269.         } else {
  270.             // we have an I4, INT or a DOUBLE
  271.             // we must check that only 0123456789-.<space> are characters here
  272.             if (!ereg("^\-?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
  273.                 $this->raiseError("Non-numeric value recieved in INT or DOUBLE", XML_RPC_ERROR_NON_NUMERIC_FOUND);
  274.                 $XML_RPC_xh[$parser]['st'] .= "ERROR_NON_NUMERIC_FOUND";
  275.             } else {
  276.                 // it's ok, add it on
  277.                 $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
  278.             }
  279.         }
  280.  
  281.         $XML_RPC_xh[$parser]['ac'] = "";
  282.         $XML_RPC_xh[$parser]['qt'] = 0;
  283.         $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
  284.         break;
  285.  
  286.     case "VALUE":
  287.         // deal with a string value
  288.         if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
  289.             $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
  290.  
  291.             $XML_RPC_xh[$parser]['st'] .= "\"" . $XML_RPC_xh[$parser]['ac'] . "\"";
  292.         }
  293.  
  294.         // This if () detects if no scalar was inside <VALUE></VALUE>
  295.         // and pads an empty "".
  296.         if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
  297.             $XML_RPC_xh[$parser]['st'] .= '""';
  298.         }
  299.         $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
  300.         if ($XML_RPC_xh[$parser]['cm']) {
  301.             $XML_RPC_xh[$parser]['st'] .= ",";
  302.         }
  303.         break;
  304.  
  305.     case "MEMBER":
  306.         $XML_RPC_xh[$parser]['ac'] = "";
  307.         $XML_RPC_xh[$parser]['qt'] = 0;
  308.         break;
  309.  
  310.     case "DATA":
  311.         $XML_RPC_xh[$parser]['ac'] = "";
  312.         $XML_RPC_xh[$parser]['qt'] = 0;
  313.         break;
  314.  
  315.     case "PARAM":
  316.         $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
  317.         break;
  318.  
  319.     case "METHODNAME":
  320.         $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", "", $XML_RPC_xh[$parser]['ac']);
  321.         break;
  322.  
  323.     case "BOOLEAN":
  324.         // special case here: we translate boolean 1 or 0 into PHP
  325.         // constants true or false
  326.         if ($XML_RPC_xh[$parser]['ac'] == '1') {
  327.             $XML_RPC_xh[$parser]['ac'] = "true";
  328.         } else {
  329.             $XML_RPC_xh[$parser]['ac'] = "false";
  330.         }
  331.  
  332.         $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  333.         break;
  334.  
  335.     default:
  336.         break;
  337.     }
  338.  
  339.     // if it's a valid type name, set the type
  340.     if (isset($XML_RPC_Types[strtolower($name)])) {
  341.         $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  342.     }
  343. }
  344.  
  345.  
  346. function XML_RPC_cd($parser, $data)
  347. {
  348.     global $XML_RPC_xh, $XML_RPC_backslash;
  349.  
  350.     if ($XML_RPC_xh[$parser]['lv'] != 3) {
  351.         // "lookforvalue==3" means that we've found an entire value
  352.         // and should discard any further character data
  353.  
  354.         if ($XML_RPC_xh[$parser]['lv'] == 1) {
  355.             // if we've found text and we're just in a <value> then
  356.             // turn quoting on, as this will be a string
  357.             $XML_RPC_xh[$parser]['qt'] = 1;
  358.             // and say we've found a value
  359.             $XML_RPC_xh[$parser]['lv'] = 2;
  360.         }
  361.  
  362.         // replace characters that eval would
  363.         // do special things with
  364.         if (isset($XML_RPC_xh[$parser]['ac'])) {
  365.             $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
  366.                 str_replace('"', '\"', str_replace(chr(92),
  367.                 $XML_RPC_backslash, $data)));
  368.         } else {
  369.             $XML_RPC_xh[$parser]['ac'] = '';
  370.         }
  371.     }
  372. }
  373.  
  374.  
  375. function XML_RPC_dh($parser, $data)
  376. {
  377.     global $XML_RPC_xh;
  378.  
  379.     if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
  380.         if ($XML_RPC_xh[$parser]['lv'] == 1) {
  381.             $XML_RPC_xh[$parser]['qt'] = 1;
  382.             $XML_RPC_xh[$parser]['lv'] = 2;
  383.         }
  384.         $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
  385.             str_replace('"', '\"', str_replace(chr(92),
  386.                 $XML_RPC_backslash, $data)));
  387.     }
  388. }
  389.  
  390. /**
  391.  * Base class
  392.  *
  393.  * This class provides common functions for all of the XML_RPC classes.
  394.  */
  395. class XML_RPC_Base {
  396.     function raiseError($msg, $code)
  397.     {
  398.         include_once 'PEAR.php';
  399.         PEAR::raiseError(get_class($this) . ": " . $msg, $code);
  400.     }
  401. }
  402.  
  403. class XML_RPC_Client extends XML_RPC_Base {
  404.     var $path;
  405.     var $server;
  406.     var $port;
  407.     var $errno;
  408.     var $errstring;
  409.     var $debug = 0;
  410.     var $username = "";
  411.     var $password = "";
  412.  
  413.     function XML_RPC_Client($path, $server, $port = 80,
  414.                             $proxy = '', $proxy_port = 8080,
  415.                             $proxy_user = '', $proxy_pass = '')
  416.     {
  417.         $this->port = $port;
  418.         $this->server = $server;
  419.         $this->path = $path;
  420.         $this->proxy = $proxy;
  421.         $this->proxy_port = $proxy_port;
  422.         $this->proxy_user = $proxy_user;
  423.         $this->proxy_pass = $proxy_pass;
  424.     }
  425.  
  426.     function setDebug($in)
  427.     {
  428.         if ($in) {
  429.             $this->debug = 1;
  430.         } else {
  431.             $this->debug = 0;
  432.         }
  433.     }
  434.  
  435.     function setCredentials($u, $p)
  436.     {
  437.         $this->username = $u;
  438.         $this->password = $p;
  439.     }
  440.  
  441.     function send($msg, $timeout = 0)
  442.     {
  443.         // where msg is an xmlrpcmsg
  444.         $msg->debug = $this->debug;
  445.         return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
  446.                                         $timeout, $this->username,
  447.                                         $this->password);
  448.     }
  449.  
  450.     function sendPayloadHTTP10($msg, $server, $port, $timeout=0,
  451.                                $username = "", $password = "")
  452.     {
  453.         // If we're using a proxy open a socket to the proxy server instead to the xml-rpc server
  454.         if ($this->proxy){
  455.             if ($timeout > 0) {
  456.                 $fp = fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr, $timeout);
  457.             } else {
  458.                 $fp = fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr);
  459.             }
  460.         } else {
  461.             if ($timeout > 0) {
  462.                 $fp = fsockopen($server, $port, $this->errno, $this->errstr, $timeout);
  463.             } else {
  464.                 $fp = fsockopen($server, $port, $this->errno, $this->errstr);
  465.             }
  466.         }
  467.  
  468.         if (!$fp && $this->proxy) {
  469.             $this->raiseError(
  470.                 "Connection to proxy server " . $this->proxy . ":" . $this->proxy_port . " failed",
  471.                 XML_RPC_ERROR_CONNECTION_FAILED);
  472.         } elseif (!$fp) {
  473.             $this->raiseError(
  474.                 "Connection to RPC server " . $this->server . " failed",
  475.                 XML_RPC_ERROR_CONNECTION_FAILED);
  476.         }
  477.  
  478.         // Only create the payload if it was not created previously
  479.         if (empty($msg->payload)) {
  480.             $msg->createPayload();
  481.         }
  482.  
  483.         // thanks to Grant Rauscher <grant7@firstworld.net> for this
  484.         $credentials = "";
  485.         if ($username != "") {
  486.             $credentials = "Authorization: Basic " .
  487.                 base64_encode($username . ":" . $password) . "\r\n";
  488.         }
  489.  
  490.  
  491.         if ($this->proxy) {
  492.             $op = "POST http://" . $this->server;
  493.  
  494.             if ($this->proxy_port) {
  495.                 $op .= ":" . $this->port;
  496.             }
  497.         } else {
  498.            $op = "POST ";
  499.         }
  500.  
  501.         $op .= $this->path. " HTTP/1.0\r\n" .
  502.                "User-Agent: PEAR XML_RPC\r\n" .
  503.                "Host: " . $this->server . "\r\n";
  504.         if ($this->proxy && $this->proxy_user != '') {
  505.             $op .= 'Proxy-Authorization: Basic ' .
  506.                 base64_encode($this->proxy_user . ':' . $this->proxy_pass) .
  507.                 "\r\n";
  508.         }
  509.         $op .= $credentials .
  510.                "Content-Type: text/xml\r\n" .
  511.                "Content-Length: " . strlen($msg->payload) . "\r\n\r\n" .
  512.                $msg->payload;
  513.  
  514.         if (!fputs($fp, $op, strlen($op))) {
  515.             $this->errstr = "Write error";
  516.             return 0;
  517.         }
  518.         $resp = $msg->parseResponseFile($fp);
  519.         fclose($fp);
  520.         return $resp;
  521.     }
  522. }
  523.  
  524.  
  525. class XML_RPC_Response extends XML_RPC_Base
  526. {
  527.     var $xv;
  528.     var $fn;
  529.     var $fs;
  530.     var $hdrs;
  531.  
  532.     function XML_RPC_Response($val, $fcode = 0, $fstr = "")
  533.     {
  534.         if ($fcode != 0) {
  535.             $this->fn = $fcode;
  536.             $this->fs = htmlspecialchars($fstr);
  537.         } else {
  538.             $this->xv = $val;
  539.         }
  540.     }
  541.  
  542.     function faultCode()
  543.     {
  544.         if (isset($this->fn)) {
  545.             return $this->fn;
  546.         } else {
  547.             return 0;
  548.         }
  549.     }
  550.  
  551.     function faultString()
  552.     {
  553.         return $this->fs;
  554.     }
  555.  
  556.     function value()
  557.     {
  558.         return $this->xv;
  559.     }
  560.  
  561.     function serialize()
  562.     {
  563.         $rs = "<methodResponse>\n";
  564.         if ($this->fn) {
  565.             $rs .= "<fault>
  566.   <value>
  567.     <struct>
  568.       <member>
  569.         <name>faultCode</name>
  570.         <value><int>" . $this->fn . "</int></value>
  571.       </member>
  572.       <member>
  573.         <name>faultString</name>
  574.         <value><string>" . $this->fs . "</string></value>
  575.       </member>
  576.     </struct>
  577.   </value>
  578. </fault>";
  579.         } else {
  580.             $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
  581.         "</param>\n</params>";
  582.         }
  583.         $rs .= "\n</methodResponse>";
  584.         return $rs;
  585.     }
  586. }
  587.  
  588.  
  589. class XML_RPC_Message extends XML_RPC_Base
  590. {
  591.     var $payload;
  592.     var $methodname;
  593.     var $params = array();
  594.     var $debug = 0;
  595.  
  596.     function XML_RPC_Message($meth, $pars = 0)
  597.     {
  598.         $this->methodname = $meth;
  599.         if (is_array($pars) && sizeof($pars)>0) {
  600.             for($i = 0; $i < sizeof($pars); $i++) {
  601.                 $this->addParam($pars[$i]);
  602.             }
  603.         }
  604.     }
  605.  
  606.     function xml_header()
  607.     {
  608.         return "<?xml version=\"1.0\"?>\n<methodCall>\n";
  609.     }
  610.  
  611.     function xml_footer()
  612.     {
  613.         return "</methodCall>\n";
  614.     }
  615.  
  616.     function createPayload()
  617.     {
  618.         $this->payload = $this->xml_header();
  619.         $this->payload .= "<methodName>" . $this->methodname . "</methodName>\n";
  620.         $this->payload .= "<params>\n";
  621.         for($i = 0; $i < sizeof($this->params); $i++) {
  622.             $p = $this->params[$i];
  623.             $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
  624.         }
  625.         $this->payload .= "</params>\n";
  626.         $this->payload .= $this->xml_footer();
  627.         $this->payload = str_replace("\n", "\r\n", $this->payload);
  628.     }
  629.  
  630.     function method($meth = "")
  631.     {
  632.         if ($meth != "") {
  633.             $this->methodname = $meth;
  634.         }
  635.         return $this->methodname;
  636.     }
  637.  
  638.     function serialize()
  639.     {
  640.         $this->createPayload();
  641.         return $this->payload;
  642.     }
  643.  
  644.     function addParam($par)
  645.     {
  646.         $this->params[] = $par;
  647.     }
  648.  
  649.     function getParam($i)
  650.     {
  651.         return $this->params[$i];
  652.     }
  653.  
  654.     function getNumParams()
  655.     {
  656.         return sizeof($this->params);
  657.     }
  658.  
  659.     function parseResponseFile($fp)
  660.     {
  661.         $ipd = "";
  662.  
  663.         while($data = fread($fp, 32768)) {
  664.             $ipd .= $data;
  665.         }
  666.         return $this->parseResponse($ipd);
  667.     }
  668.  
  669.     function parseResponse($data = "")
  670.     {
  671.         global $XML_RPC_xh,$XML_RPC_err,$XML_RPC_str;
  672.         global $XML_RPC_defencoding;
  673.  
  674.         $parser = xml_parser_create($XML_RPC_defencoding);
  675.  
  676.         $XML_RPC_xh[$parser] = array();
  677.  
  678.         $XML_RPC_xh[$parser]['st'] = "";
  679.         $XML_RPC_xh[$parser]['cm'] = 0;
  680.         $XML_RPC_xh[$parser]['isf'] = 0;
  681.         $XML_RPC_xh[$parser]['ac'] = "";
  682.         $XML_RPC_xh[$parser]['qt'] = "";
  683.  
  684.         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
  685.         xml_set_element_handler($parser, "XML_RPC_se", "XML_RPC_ee");
  686.         xml_set_character_data_handler($parser, "XML_RPC_cd");
  687.         xml_set_default_handler($parser, "XML_RPC_dh");
  688.         $xmlrpc_value = new XML_RPC_Value;
  689.  
  690.         $hdrfnd = 0;
  691.         if ($this->debug) {
  692.             print "<PRE>---GOT---\n";
  693.             print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
  694.             print "\n---END---\n</PRE>";
  695.         }
  696.  
  697.         // see if we got an HTTP 200 OK, else bomb
  698.         // but only do this if we're using the HTTP protocol.
  699.         if (ereg("^HTTP",$data) &&
  700.             !ereg("^HTTP/[0-9\.]+ 200 ", $data)) {
  701.                 $errstr = substr($data, 0, strpos($data, "\n")-1);
  702.                 error_log("HTTP error, got response: " . $errstr);
  703.                 $r = new XML_RPC_Response(0, $XML_RPC_err["http_error"],
  704.                                           $XML_RPC_str["http_error"] . " (" .
  705.                                           $errstr . ")");
  706.                 xml_parser_free($parser);
  707.                 return $r;
  708.         }
  709.         // gotta get rid of headers here
  710.  
  711.  
  712.         if ((!$hdrfnd) && ($brpos = strpos($data,"\r\n\r\n"))) {
  713.             $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
  714.             $data = substr($data, $brpos + 4);
  715.             $hdrfnd = 1;
  716.         }
  717.  
  718.         // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
  719.         // thanks to Luca Mariano <luca.mariano@email.it>
  720.         $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
  721.  
  722.         if (!xml_parse($parser, $data, sizeof($data))) {
  723.             // thanks to Peter Kocks <peter.kocks@baygate.com>
  724.             if ((xml_get_current_line_number($parser)) == 1) {
  725.                 $errstr = "XML error at line 1, check URL";
  726.             } else {
  727.                 $errstr = sprintf("XML error: %s at line %d",
  728.                                   xml_error_string(xml_get_error_code($parser)),
  729.                                   xml_get_current_line_number($parser));
  730.             }
  731.             error_log($errstr);
  732.             $r = new XML_RPC_Response(0, $XML_RPC_err["invalid_return"],
  733.                                       $XML_RPC_str["invalid_return"]);
  734.             xml_parser_free($parser);
  735.             return $r;
  736.         }
  737.         xml_parser_free($parser);
  738.         if ($this->debug) {
  739.             print "<PRE>---EVALING---[" .
  740.             strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
  741.             htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---</PRE>";
  742.         }
  743.         if (strlen($XML_RPC_xh[$parser]['st']) == 0) {
  744.             // then something odd has happened
  745.             // and it's time to generate a client side error
  746.             // indicating something odd went on
  747.             $r = new XML_RPC_Response(0, $XML_RPC_err["invalid_return"],
  748.                                          $XML_RPC_str["invalid_return"]);
  749.         } else {
  750.             eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;');
  751.             if ($XML_RPC_xh[$parser]['isf']) {
  752.                 $f = $v->structmem("faultCode");
  753.                 $fs = $v->structmem("faultString");
  754.                 $r = new XML_RPC_Response($v, $f->scalarval(),
  755.                                               $fs->scalarval());
  756.             } else {
  757.                 $r = new XML_RPC_Response($v);
  758.             }
  759.         }
  760.         $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
  761.         return $r;
  762.     }
  763.  
  764. }
  765.  
  766.  
  767. class XML_RPC_Value extends XML_RPC_Base
  768. {
  769.     var $me = array();
  770.     var $mytype = 0;
  771.  
  772.     function XML_RPC_Value($val = -1, $type = "")
  773.     {
  774.         global $XML_RPC_Types;
  775.         $this->me = array();
  776.         $this->mytype = 0;
  777.         if ($val != -1 || $type != "") {
  778.             if ($type == "") {
  779.                 $type="string";
  780.             }
  781.             if ($XML_RPC_Types[$type] == 1) {
  782.                 $this->addScalar($val,$type);
  783.             } elseif ($XML_RPC_Types[$type] == 2) {
  784.                 $this->addArray($val);
  785.             } elseif ($XML_RPC_Types[$type] == 3) {
  786.                 $this->addStruct($val);
  787.             }
  788.         }
  789.     }
  790.  
  791.     function addScalar($val, $type = "string")
  792.     {
  793.         global $XML_RPC_Types, $XML_RPC_Boolean;
  794.  
  795.         if ($this->mytype == 1) {
  796.             $this->raiseError("Scalar can have only one value", XML_RPC_ERROR_INVALID_TYPE);
  797.             return 0;
  798.         }
  799.         $typeof = $XML_RPC_Types[$type];
  800.         if ($typeof != 1) {
  801.             $this->raiseError("Not a scalar type (${typeof})", XML_RPC_ERROR_INVALID_TYPE);
  802.             return 0;
  803.         }
  804.  
  805.         if ($type == $XML_RPC_Boolean) {
  806.             if (strcasecmp($val,"true") == 0 ||
  807.                 $val == 1 ||
  808.                 ($val == true &&
  809.                     strcasecmp($val,"false"))) {
  810.  
  811.                 $val = 1;
  812.             } else {
  813.                 $val = 0;
  814.             }
  815.         }
  816.  
  817.         if ($this->mytype == 2) {
  818.             // we're adding to an array here
  819.             $ar = $this->me["array"];
  820.             $ar[] = new XML_RPC_Value($val, $type);
  821.             $this->me["array"] = $ar;
  822.         } else {
  823.             // a scalar, so set the value and remember we're scalar
  824.             $this->me[$type] = $val;
  825.             $this->mytype = $typeof;
  826.         }
  827.         return 1;
  828.     }
  829.  
  830.     function addArray($vals)
  831.     {
  832.         global $XML_RPC_Types;
  833.         if ($this->mytype != 0) {
  834.             $this->raiseError(
  835.                 "Already initialized as a [" . $this->kindOf() . "]",
  836.                 XML_RPC_ERROR_ALREADY_INITIALIZED);
  837.             return 0;
  838.         }
  839.         $this->mytype = $XML_RPC_Types["array"];
  840.         $this->me["array"] = $vals;
  841.         return 1;
  842.     }
  843.  
  844.     function addStruct($vals)
  845.     {
  846.         global $XML_RPC_Types;
  847.         if ($this->mytype != 0) {
  848.             $this->raiseError(
  849.                 "Already initialized as a [" . $this->kindOf() . "]",
  850.                 XML_RPC_ERROR_ALREADY_INITIALIZED);
  851.             return 0;
  852.         }
  853.         $this->mytype = $XML_RPC_Types["struct"];
  854.         $this->me["struct"] = $vals;
  855.         return 1;
  856.     }
  857.  
  858.     function dump($ar)
  859.     {
  860.         reset($ar);
  861.         while (list( $key, $val ) = each($ar)) {
  862.             echo "$key => $val<br>";
  863.             if ($key == 'array') {
  864.                 while ( list( $key2, $val2 ) = each( $val ) ) {
  865.                     echo "-- $key2 => $val2<br>";
  866.                 }
  867.             }
  868.         }
  869.     }
  870.  
  871.     function kindOf()
  872.     {
  873.         switch ($this->mytype) {
  874.         case 3:
  875.             return "struct";
  876.             break;
  877.         case 2:
  878.             return "array";
  879.             break;
  880.         case 1:
  881.             return "scalar";
  882.             break;
  883.         default:
  884.             return "undef";
  885.         }
  886.     }
  887.  
  888.     function serializedata($typ, $val)
  889.     {
  890.         $rs = "";
  891.         global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean;
  892.         switch ($XML_RPC_Types[$typ]) {
  893.         case 3:
  894.             // struct
  895.             $rs .= "<struct>\n";
  896.             reset($val);
  897.             while(list($key2, $val2) = each($val)) {
  898.                 $rs .= "<member><name>${key2}</name>\n";
  899.                 $rs .= $this->serializeval($val2);
  900.                 $rs .= "</member>\n";
  901.             }
  902.             $rs .= "</struct>";
  903.             break;
  904.         case 2:
  905.             // array
  906.             $rs .= "<array>\n<data>\n";
  907.             for($i = 0; $i < sizeof($val); $i++) {
  908.                 $rs .= $this->serializeval($val[$i]);
  909.             }
  910.             $rs .= "</data>\n</array>";
  911.             break;
  912.         case 1:
  913.             switch ($typ) {
  914.             case $XML_RPC_Base64:
  915.                 $rs .= "<${typ}>" . base64_encode($val) . "</${typ}>";
  916.                 break;
  917.             case $XML_RPC_Boolean:
  918.                 $rs .= "<${typ}>" . ($val ? "1" : "0") . "</${typ}>";
  919.                 break;
  920.             case $XML_RPC_String:
  921.                 $rs .= "<${typ}>" . htmlspecialchars($val). "</${typ}>";
  922.                 break;
  923.             default:
  924.                 $rs .= "<${typ}>${val}</${typ}>";
  925.             }
  926.             break;
  927.         default:
  928.             break;
  929.         }
  930.         return $rs;
  931.     }
  932.  
  933.     function serialize()
  934.     {
  935.         return $this->serializeval($this);
  936.     }
  937.  
  938.     function serializeval($o)
  939.     {
  940.         $rs = "";
  941.         $ar = $o->me;
  942.         reset($ar);
  943.         list($typ, $val) = each($ar);
  944.         $rs .= "<value>";
  945.         $rs .= $this->serializedata($typ, $val);
  946.         $rs .= "</value>\n";
  947.         return $rs;
  948.     }
  949.  
  950.     function structmem($m)
  951.     {
  952.         $nv = $this->me["struct"][$m];
  953.         return $nv;
  954.     }
  955.  
  956.     function structreset()
  957.     {
  958.         reset($this->me["struct"]);
  959.     }
  960.  
  961.     function structeach()
  962.     {
  963.         return each($this->me["struct"]);
  964.     }
  965.  
  966.     function getval() {
  967.         // UNSTABLE
  968.         global $XML_RPC_BOOLEAN, $XML_RPC_Base64;
  969.  
  970.         reset($this->me);
  971.         list($a,$b) = each($this->me);
  972.  
  973.         // contributed by I Sofer, 2001-03-24
  974.         // add support for nested arrays to scalarval
  975.         // i've created a new method here, so as to
  976.         // preserve back compatibility
  977.  
  978.         if (is_array($b)) {
  979.             foreach ($b as $id => $cont) {
  980.                 $b[$id] = $cont->scalarval();
  981.             }
  982.         }
  983.  
  984.         // add support for structures directly encoding php objects
  985.         if (is_object($b)) {
  986.             $t = get_object_vars($b);
  987.             foreach ($t as $id => $cont) {
  988.                 $t[$id] = $cont->scalarval();
  989.             }
  990.             foreach ($t as $id => $cont) {
  991.                 eval('$b->'.$id.' = $cont;');
  992.             }
  993.         }
  994.  
  995.         // end contrib
  996.         return $b;
  997.     }
  998.  
  999.     function scalarval()
  1000.     {
  1001.         global $XML_RPC_Boolean, $XML_RPC_Base64;
  1002.         reset($this->me);
  1003.         list($a,$b) = each($this->me);
  1004.         return $b;
  1005.     }
  1006.  
  1007.     function scalartyp()
  1008.     {
  1009.         global $XML_RPC_I4, $XML_RPC_Int;
  1010.         reset($this->me);
  1011.         list($a,$b) = each($this->me);
  1012.         if ($a == $XML_RPC_I4) {
  1013.             $a = $XML_RPC_Int;
  1014.         }
  1015.         return $a;
  1016.     }
  1017.  
  1018.     function arraymem($m)
  1019.     {
  1020.         $nv = $this->me["array"][$m];
  1021.         return $nv;
  1022.     }
  1023.  
  1024.     function arraysize()
  1025.     {
  1026.         reset($this->me);
  1027.         list($a,$b) = each($this->me);
  1028.         return sizeof($b);
  1029.     }
  1030. }
  1031.  
  1032.  
  1033. /**
  1034.  * date helpers
  1035.  */
  1036. function XML_RPC_iso8601_encode($timet, $utc = 0) {
  1037.     // return an ISO8601 encoded string
  1038.     // really, timezones ought to be supported
  1039.     // but the XML-RPC spec says:
  1040.     //
  1041.     // "Don't assume a timezone. It should be specified by the server in its
  1042.     // documentation what assumptions it makes about timezones."
  1043.     //
  1044.     // these routines always assume localtime unless
  1045.     // $utc is set to 1, in which case UTC is assumed
  1046.     // and an adjustment for locale is made when encoding
  1047.     if (!$utc) {
  1048.         $t = strftime("%Y%m%dT%H:%M:%S", $timet);
  1049.     } else {
  1050.         if (function_exists("gmstrftime")) {
  1051.             // gmstrftime doesn't exist in some versions
  1052.             // of PHP
  1053.             $t = gmstrftime("%Y%m%dT%H:%M:%S", $timet);
  1054.         } else {
  1055.             $t = strftime("%Y%m%dT%H:%M:%S", $timet - date("Z"));
  1056.         }
  1057.     }
  1058.  
  1059.     return $t;
  1060. }
  1061.  
  1062. function XML_RPC_iso8601_decode($idate, $utc = 0) {
  1063.     // return a timet in the localtime, or UTC
  1064.     $t = 0;
  1065.     if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs)) {
  1066.  
  1067.         if ($utc) {
  1068.             $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  1069.         } else {
  1070.             $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  1071.         }
  1072.     }
  1073.  
  1074.     return $t;
  1075. }
  1076.  
  1077. /**
  1078.  * Takes a message in PHP XML_RPC object format and translates it into native PHP types.
  1079.  *
  1080.  * @author Dan Libby <dan@libby.com>
  1081.  **/
  1082. function XML_RPC_decode($XML_RPC_val) {
  1083.     $kind = $XML_RPC_val->kindOf();
  1084.  
  1085.    if ($kind == "scalar") {
  1086.       return $XML_RPC_val->scalarval();
  1087.  
  1088.    } elseif ($kind == "array") {
  1089.       $size = $XML_RPC_val->arraysize();
  1090.       $arr = array();
  1091.  
  1092.       for($i = 0; $i < $size; $i++) {
  1093.          $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
  1094.       }
  1095.       return $arr;
  1096.  
  1097.    } elseif ($kind == "struct") {
  1098.       $XML_RPC_val->structreset();
  1099.       $arr = array();
  1100.  
  1101.       while(list($key,$value) = $XML_RPC_val->structeach()) {
  1102.          $arr[$key] = XML_RPC_decode($value);
  1103.       }
  1104.       return $arr;
  1105.    }
  1106. }
  1107.  
  1108. /**
  1109.  * Takes native php types and encodes them into XML_RPC PHP object format.
  1110.  *
  1111.  * Feature creep -- could support more types via optional type argument.
  1112.  *
  1113.  * @author Dan Libby <dan@libby.com>
  1114.  **/
  1115. function XML_RPC_encode($php_val) {
  1116.    global $XML_RPC_Boolean;
  1117.    global $XML_RPC_Int;
  1118.    global $XML_RPC_Double;
  1119.    global $XML_RPC_String;
  1120.    global $XML_RPC_Array;
  1121.    global $XML_RPC_Struct;
  1122.  
  1123.    $type = gettype($php_val);
  1124.    $XML_RPC_val = new XML_RPC_Value;
  1125.  
  1126.    switch ($type) {
  1127.    case "array":
  1128.        $keys = array_keys($php_val);
  1129.        $count = count($php_val);
  1130.        $firstkey = $keys[0];
  1131.        $lastkey = $keys[$count - 1];
  1132.        if ($firstkey === 0 && is_int($lastkey) && ($lastkey + 1) == $count) {
  1133.            $is_continuous = true;
  1134.            $expected = 0;
  1135.            foreach ($keys as $actual) {
  1136.                if ($actual != $expected) {
  1137.                    $is_continuous = false;
  1138.                    break;
  1139.                }
  1140.                $expected++;
  1141.            }
  1142.  
  1143.            if ($is_continuous) {
  1144.                $arr = array();
  1145.                foreach ($php_val as $k => $v) {
  1146.                    $arr[$k] = XML_RPC_encode($v);
  1147.                }
  1148.                $XML_RPC_val->addArray($arr);
  1149.                break;
  1150.            }
  1151.        }
  1152.        // fall though if not numerical and continuous
  1153.    case "object":
  1154.        $arr = array();
  1155.        foreach ($php_val as $k => $v) {
  1156.            $arr[$k] = XML_RPC_encode($v);
  1157.        }
  1158.        $XML_RPC_val->addStruct($arr);
  1159.        break;
  1160.  
  1161.    case "integer":
  1162.        $XML_RPC_val->addScalar($php_val, $XML_RPC_Int);
  1163.        break;
  1164.  
  1165.    case "double":
  1166.        $XML_RPC_val->addScalar($php_val, $XML_RPC_Double);
  1167.        break;
  1168.  
  1169.    case "string":
  1170.    case "NULL":
  1171.        $XML_RPC_val->addScalar($php_val, $XML_RPC_String);
  1172.        break;
  1173.  
  1174.    // <G_Giunta_2001-02-29>
  1175.    // Add support for encoding/decoding of booleans, since they are supported in PHP
  1176.    case "boolean":
  1177.        $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean);
  1178.        break;
  1179.    // </G_Giunta_2001-02-29>
  1180.  
  1181.    case "unknown type":
  1182.    default:
  1183.        $XML_RPC_val = false;
  1184.        break;
  1185.    }
  1186.    return $XML_RPC_val;
  1187. }
  1188.  
  1189. ?>
  1190.